#include "HMAC.h"
void HMAC::paddingDeCeros(std::string& bytes)
{
    while ( bytes.size() < TAM_BLOQUE )
    {
        bytes.push_back(0);
        //nota interesante :
        // bytes.push_back('0') hace cualquier cosa
    }
}

void HMAC::VerificarLongitudKey(std::string& K)
{
    if ( K.size() > TAM_BLOQUE )
    {
        K = MD5(K).hexdigest();
    }
}
void HMAC::ConvertirHexABin(std::string& Bytes)
{
    unsigned int size = ceil(Bytes.size()/2);
    char* Bin = new char[size+1];
    Bin[size]='\0';
    const char* P = Bytes.c_str();
    char DosDigitosEnHexa[3];
    DosDigitosEnHexa[2] = '\0';
    unsigned int PosicionArchivo = 0;
    //OJO : i += 2 !!!
    for(unsigned int i = 0 ; i < (strlen(P)) ; i = i + 2)
    {
        DosDigitosEnHexa[0] = P[i];
        DosDigitosEnHexa[1] = P[i+1];
        Bin[PosicionArchivo]= strtol(DosDigitosEnHexa,NULL,16);
        PosicionArchivo++;
    }
    Bytes = std::string(Bin);
    delete[] Bin;
}

void HMAC::XOR(unsigned char* bytes,unsigned char Xpad)
{
    for ( int i = 0 ; i < TAM_BLOQUE ; i++ )
    {
        bytes[i] ^= Xpad ;
    }
}

HMAC::HMAC(const std::string& KEY,const unsigned char* MSJ,unsigned int SizeMsj )
{
    //std::cout << "begin hmac" << std::endl;
    this->Const_ipad = 0x36;
    this->Const_opad = 0x5c;
    std::string KeyAux = KEY;
    //si la longitud de la clave es mayor que la del bloque, se la hashea
    // y se usa lo hasheado como clave
    this->VerificarLongitudKey(KeyAux);
    //(1) append zeros to the end of K to create a TAM_BLOQUE byte string
    this->paddingDeCeros(KeyAux);

    unsigned char KEYi[TAM_BLOQUE+1];
    KEYi[TAM_BLOQUE]='\0';
    unsigned char KEYo[TAM_BLOQUE+1];
    KEYo[TAM_BLOQUE]='\0';
    memcpy(KEYi,KeyAux.c_str(),TAM_BLOQUE);
    memcpy(KEYo,KeyAux.c_str(),TAM_BLOQUE);
    //(2) XOR the TAM_BLOQUE byte string computed in step(1) with ipad
    this->XOR(KEYi,this->Const_ipad);
    //(3) append the data to the TAM_BLOQUE byte string resulting from step (2)
    //(4) apply H to the stream generated in step (3)
    MD5 md5I;
    md5I.update(KEYi,TAM_BLOQUE);
    md5I.update(MSJ,SizeMsj);
    md5I.finalize();
    std::string primerP = md5I.hexdigest();
    //std::cout << "primerP:"<<primerP << std::endl;
    this->ConvertirHexABin(primerP);
    //(5) XOR the TAM_BLOQUE byte string computed in step (1) with opad
    this->XOR(KEYo,this->Const_opad);
    //(6) append result from step (4) to the TAM_BLOQUE byte string from step (5)
    //(7) apply H to the stream generated in step (6) and output the result
    MD5 md5O;
    md5O.update(KEYo,TAM_BLOQUE);
    md5O.update(primerP.c_str(),primerP.size());
    md5O.finalize();
    this->resultado = md5O.hexdigest();
    //std::cout << this->resultado << std::endl;
    //std::cout << "end hmac" << std::endl;
}
